package cn.agiledata.bank.transaction.action;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import ocx.AESWithJCE;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import cn.agiledata.bank.account.service.AccountSummary;
import cn.agiledata.bank.account.service.IAccountService;
import cn.agiledata.bank.common.dao.AccountTemplateInter;
import cn.agiledata.bank.common.service.PermissionService;
import cn.agiledata.bank.common.service.SetUpUses;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.ConvertUtil;
import cn.agiledata.bank.common.util.ForeDict;
import cn.agiledata.bank.common.util.WeatherUtil;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.Groups;
import cn.agiledata.bank.hibernateBean.Operator;
import cn.agiledata.bank.hibernateBean.SubAccount;
import cn.agiledata.bank.hibernateBean.Transaction;
import cn.agiledata.bank.linkbank.action.WebPayRequestAction;
import cn.agiledata.bank.linkbank.action.UnsPayResponseAction;
import cn.agiledata.bank.linkbank.logic.payment.UnsPayRequest;
import cn.agiledata.bank.linkbank.logic.payment.UnsPayResponse;
import cn.agiledata.bank.linkbank.service.WebPayService;
import cn.agiledata.bank.transaction.exception.TransactionException;
import cn.agiledata.bank.transaction.form.InnerPayForm;
import cn.agiledata.bank.transaction.form.InnerTransactForm;
import com.vnv.infrastructure.logic.IPBAppFactory;

/**
 * 账户间支付交易Action
 * 
 * @author maxianbo
 * 
 */
public class InnerPayAction extends InnerTransactAction {

    protected SubAccount getCreditSubAccount(InnerTransactForm innerTransactForm) {
        InnerPayForm form = (InnerPayForm) innerTransactForm;
        Account creditAccount = getAccountTemplate().getAccountByName(
                form.getCredit().trim());
        return creditAccount == null ? null : creditAccount
                .getDefaultSubAccount();
    }

    protected SubAccount getDebitSubAccount(InnerTransactForm innerTransactForm) {
        InnerPayForm form = (InnerPayForm) innerTransactForm;
        String debitSubAccountId = String.valueOf(form.getDebitSubAccountId());
        return getAccountTemplate().getSubAccount(debitSubAccountId);
    }

    protected void setTransactionStautsByAssured(Transaction trans,
            boolean assured) {
        if (assured) {
            // 担保交易
            trans.setTradeType(Constant.TRADE_TYPE_ASSURE);
            // 担保交易的交易状态：买方已付款等待卖家发货
            trans.setTransStatus(Constant.TRANS_STATUS_WAITFORBUYER);
            // 担保交易的内部状态：不进行实际转账操作
            trans.setInsideStatus(Constant.INSIDE_STATUS_NO);
        } else {
            // 非担保交易
            trans.setTradeType(Constant.TRADE_TYPE_NOASSURE);
            // 非担保交易的交易状态：交易成功
            trans.setTransStatus(Constant.TRANS_STATUS_TRANSACTIONSUCCESS);
            // 非担保交易的内部状态：进行实际转账操作
            trans.setInsideStatus(Constant.INSIDE_STATUS_YES);
            trans.setEndDate(new Date());//设置截止日期
        }
        // 设置记账模型
        trans.setOperate(Constant.MODEL_TYPE_PAYMONEY);
    }

    /**
     * 设置费率收取方式
     */
    private void loadFeeRatioMode(HttpServletRequest request) {
        Groups group = getMySpaceService().getGroupByAccount(
                getCurrentAccount(request), Constant.GROUP_TYPE_A);
        String feeRatioMode = getFeeRatioService().getFeeRatio(group,
                getActionType());
        request.setAttribute("feeRatioMode", feeRatioMode);
    }

    /**
     * 个人用户校验支付密码
     */
    private void validatePassword(HttpServletRequest request, String password)
            throws TransactionException {
        Account account = getCurrentAccount(request);
        if (isPersonAccount(account)) { // 个人用户校验账户支付密码
            if (!getAccountTemplate().compareAccountPickUpPassword(account,
                    password)) {
                // throw TransactionException.PAY_PASSWORD_ERROR;

                IAccountService accountService = (IAccountService) IPBAppFactory
                        .getObj(ForeDict.SERVICE_ACCOUNT);

                // 记入系统日志
                accountService.writeSystemLogWhenPayPasswordError(account,
                        request.getRemoteAddr());

                // 获取账户当日支付密码输错次数
                int currentPayPwdErr = accountService
                        .getCurrentPayPwdErrByAccountId(account.getId());

                // 获取系统允许的当日支付密码累计输错次数上限(大于这个值就锁定该账户，明日才能登录)
                int maxPayPwdErr = accountService.getMaxPayPwdErrFromSysBook();

                if (currentPayPwdErr <= maxPayPwdErr) {// 支付密码输入错误，且当日累计输错次数小于或等于系统所允许的上限值--->抛异常
                    throw TransactionException.getPayPasswordError(String
                            .valueOf(currentPayPwdErr), String
                            .valueOf(maxPayPwdErr));
                } else {// 支付密码输入错误，且当日累计输错次数大于系统所允许的上限值--->锁定账户，抛异常
                    String sign = account.getEmail() == null ? account
                            .getMobile() : account.getEmail();
                    accountService.lockAccountLoginBySign(sign);

                    throw TransactionException
                            .getPayPasswordErrorNeedLogout(String
                                    .valueOf(maxPayPwdErr));
                }
            }
        } else if (isFromMerchant(request)) { // 企业用户且为商户支付请求，校验操作员支付密码
            Operator operator = WeatherUtil.getOperator(request);
            if (operator != null
                    && !getAccountTemplate().corCompareAccountPickUpPassword(
                            operator, password)) {
                throw TransactionException.PAY_PASSWORD_ERROR;
            }
        }
    }

    private UnsPayRequest getMerchantUnsPayRequest(HttpSession session) {
        return (UnsPayRequest) session
                .getAttribute(WebPayRequestAction.UNS_PAY_REQUEST);
    }

    private boolean isFromMerchant(HttpServletRequest request) {
        return getMerchantUnsPayRequest(request.getSession()) != null;
    }

    private void loadMerchantRequestAttributes(HttpServletRequest request) {
        UnsPayRequest unsPayRequest = getMerchantUnsPayRequest(request
                .getSession());
        if (unsPayRequest != null) {
            request.setAttribute("creditAccount", unsPayRequest
                    .getCreditAccount());
            request.setAttribute("amount", unsPayRequest.getAmount());
            request.setAttribute("assuredPay", new Boolean(unsPayRequest
                    .isAssuredPay()));
            request.setAttribute("commodity", "");
            request.setAttribute("remark", unsPayRequest.getRemark());
        }
    }

    private void loadTransactionToForm(InnerPayForm form) {
        String transId = form.getTransId();
        if (transId != null && transId.length() > 0) {
            Transaction trans = getTransactionTemplate()
                    .getTransactionByTranId(transId);
            if (trans != null) {
                form.setDebitSubAccountId(trans.getDebit().getId().longValue());
                if (StringUtils.isNotEmpty(trans.getCredit().getAccount()
                        .getEmail())) {
                    form.setCredit(trans.getCredit().getAccount().getEmail());
                } else {
                    form.setCredit(trans.getCredit().getAccount().getMobile());
                }
                form.setAmount(trans.getAmount().toString());
                form.setAssured(Constant.TRADE_TYPE_ASSURE.equals(trans
                        .getTradeType()));
                form.setCommodity(trans.getCommodityInfo());
                form.setPurpose(trans.getPurpose());
                form.setRemark(trans.getRemark());
            }
        }
    }

    private void prepareMerchant(HttpServletRequest request) {
        if ("merchant".equals(request.getParameter("from"))) {
            loadMerchantRequestAttributes(request);
        } else {
            clearMerchant(request.getSession());
        }
    }

    private void postMerchant(HttpServletRequest request, Transaction trans) {
        HttpSession session = request.getSession();
        UnsPayRequest unsPayRequest = getMerchantUnsPayRequest(session);
        if (unsPayRequest != null) {
            WebPayService webPayService = (WebPayService) IPBAppFactory
                    .getObj(ForeDict.SERVICE_WEB_PAY);
            // 内部交易可能未预先提供订单号，此时用生成的交易编号代替
            if (unsPayRequest.getOrderId() == null
                    || unsPayRequest.getOrderId().length() == 0) {
                unsPayRequest.setOrderId(trans.getTransId());
            }
            unsPayRequest.setAffirmable(false); // 不需要确认
            UnsPayResponse unsPayResponse = webPayService.getUnsPayResponse(
                    unsPayRequest, false);
            session.setAttribute(UnsPayResponseAction.UNSPAYRESPONSE_KEY,
                    unsPayResponse);
            clearMerchant(session);
        }
    }

    private void clearMerchant(HttpSession session) {
        session.removeAttribute(WebPayRequestAction.UNS_PAY_REQUEST_FORM);
        session.removeAttribute(WebPayRequestAction.UNS_PAY_REQUEST);
    }

    /**
     * 校验账户信息
     * 
     * @param creditKey
     *            收款方的账户关键字段，如email，手机，或账户编号
     * @param subAccount2Id
     *            付款方子账户
     * @return 根据收款方的账户关键字段获取的主账户
     */
    protected final Account validateAccount(String creditKey, SubAccount debit,
            boolean fromMerchant) throws TransactionException {
        Account credit = WeatherUtil.getAccountByEmail(creditKey.trim());
        if (credit == null) {
            throw TransactionException.UNEXISTED_ACCOUNT;
        } else if (Constant.ACCOUNT_TYPE_INITIAL
                .equals(credit.getAccountType())
                && !fromMerchant) {
            // 内部账户且非商户请求，不能进行直接交易
            throw TransactionException.UNEXISTED_ACCOUNT;
        } else if (credit.getId().longValue() == debit.getAccount().getId()
                .longValue()) {
            throw TransactionException.THE_SAME_DEBIT_CREDIT;
        }
        getTransactionService().validateTransactable(debit.getAccount(),
                credit, credit.getName(), Constant.ACTION_TYPE_C);
        return credit;
    }

    public ActionForward prepare(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        prepareMerchant(request);

        // 判断当前用户是否具有付款权限
        PermissionService permissionService = PermissionService
                .getPermissionService();
        if (!permissionService.hasPermission(request,
                Constant.PERMIS_TYPE_PAYMONEY)) {
            handleAppException(mapping, actionForm, request, response,
                    TransactionException.NO_PERMISSION);
        }

        Account account = getCurrentAccount(request);
        loadSubAccountList(request);
        // 付款子账户默认选择默认子账户
        InnerPayForm form = (InnerPayForm) actionForm;
        if (form.getDebitSubAccountId() == 0) {
            SubAccount defaultSubAccount = account.getDefaultSubAccount();
            form.setDebitSubAccountId(defaultSubAccount.getId().longValue());
        }
        loadFeeRatioMode(request);
        // 设置交易类型默认为担保交易
        form.setAssured(true);
        return mapping.findForward(ForeDict.FORWARD_STEP_1);
    }

    public ActionForward fill(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        InnerPayForm form = (InnerPayForm) actionForm;
        loadTransactionToForm(form);
        try {
        	String subAccountId = String.valueOf(form.getDebitSubAccountId());
        	SubAccount subAccount = getAccountTemplate().getSubAccount(
        			subAccountId);
        	Account curAccount = getCurrentAccount(request);
            Account account = subAccount.getAccount();
            if (!curAccount.equals(account)) {
            	throw TransactionException.NOT_THE_SAME_ACCOUNT;
            }
            // 判断当前用户是否具有付款权限
            PermissionService permissionService = PermissionService
                    .getPermissionService();
            if (!permissionService.hasPermission(request,
                    Constant.PERMIS_TYPE_PAYMONEY)) {
                if (form.getTransId() != null && form.getTransId().length() > 0) {
                    handleAppException(mapping, actionForm, request, response,
                            TransactionException.NO_PERMISSION);
                } else {
                    throw TransactionException.NO_PERMISSION;
                }
            }

            Double amount = validateAmount(form.getAmount());

            // 获取付款的手续费
            double debitFee = getDebitFee(subAccount, amount);

            // 校验付款方子账户余额
            validateDebitSubAccountBalance(subAccount, amount, debitFee);

            // 校验付款方金额限制
            //validateAccountLimit(account, amount.doubleValue());//付款不需要金额限制，故注释掉

            // 加载并校验收款方账户信息
            Account creditAccount = validateAccount(form.getCredit(),
                    subAccount, isFromMerchant(request));

            // 校验收款方实际收款是否大于0
            validateCreditAccountReceiveAmount(creditAccount, amount);

            request.setAttribute("amount", amount);
            request.setAttribute("fee", new Double(debitFee));
            request.setAttribute("subAccount", subAccount);
            request.setAttribute("creditAccount", creditAccount);
            request.setAttribute("assured", new Boolean(form.isAssured()));
            if (getCommonService().compareAmounts(subAccountId, getActionType(), amount) != 0) {
                // 生成充值金额低于费率的异常
            	//request.removeAttribute("amount");
            	request.setAttribute("amount", null);
                throw TransactionException.getAmountUnderFeeException(amount
                        .doubleValue(), debitFee);
            }
        } catch (TransactionException e) {
            // 处理业务逻辑异常
            handleAppException(mapping, actionForm, request, response, e);
            // 跳转到第1步，之前重新装载子账户列表
            loadSubAccountList(request);
            // 重新加载商户请求数据
            loadMerchantRequestAttributes(request);
            // 设置费率收取方式
            loadFeeRatioMode(request);
            // 设置为上一步的步骤序数，防止序数与步骤不同步
            form.setPreviousStep();
            return mapping.findForward(ForeDict.FORWARD_STEP_1);
        }
        // 加载是否需要输入支付密码
        loadRequiredPassword(request);

        saveToken(request);
        return mapping.findForward(ForeDict.FORWARD_STEP_2);
    }

    /**
     * 加载是否需要输入支付密码
     */
    private void loadRequiredPassword(HttpServletRequest request) {
        boolean personAccount = isPersonAccount(request);
        boolean fromMerchant = isFromMerchant(request);
        request.setAttribute("requiredPassword", new Boolean(personAccount
                || fromMerchant));
    }

    public ActionForward transact(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        InnerPayForm form = (InnerPayForm) actionForm;
        String debitSubAccountId = String.valueOf(form.getDebitSubAccountId());
        AccountTemplateInter accountTemplate = getAccountTemplate();
        SubAccount debitSubAccount = accountTemplate
                .getSubAccount(debitSubAccountId);
        boolean fromMerchant = isFromMerchant(request); // 是否商户支付请求

        // 加载并校验收款方账户信息
        Account creditAccount = validateAccount(form.getCredit(),
                debitSubAccount, fromMerchant);
        //如果是手机充值账户,跳转到系统错误页面
        Account temp = getCurrentAccount(request);
        String accountType = temp.getAccountType();
        if (creditAccount.getAccountId().equals("11") && accountType.equals(Constant.ACCOUNT_TYPE_CORPORATION)) {
        	return mapping.findForward("payerror");
        }

        // 此处加载收款方账户的目的是，出现业务逻辑异常返回第二步时，页面要用到该账户。
        // 正常流程中此账户无用，在此处加载是为了提高效率
        request.setAttribute("creditAccount", creditAccount);
        try {
            if (!isTokenValid(request)) {
                throw TransactionException.REPEATEDLY_SUBMIT;
            }

            // 判断当前用户是否具有付款权限
            PermissionService permissionService = PermissionService
                    .getPermissionService();
            if (!permissionService.hasPermission(request,
                    Constant.PERMIS_TYPE_PAYMONEY)) {
                throw TransactionException.NO_PERMISSION;
            }

            Double amount = validateAmount(form.getAmount());

            // 获取付款的手续费
            double debitFee = getDebitFee(debitSubAccount, amount);

            // 校验付款方子账户余额
            validateDebitSubAccountBalance(debitSubAccount, amount, debitFee);

            // 校验付款方金额限制
            Account debitAccount = debitSubAccount.getAccount();
            //validateAccountLimit(debitAccount, amount.doubleValue());//付款不需要金额限制，故注释掉

            // 校验收款方实际收款金额是否大于0
            validateCreditAccountReceiveAmount(creditAccount, amount);

            try {
            	HttpSession session = request.getSession();
        		String mcrypt_key_1=(String)session.getAttribute("mcrypt_key");//获取session中随机因子
        		session.removeAttribute("mcrypt_key");//清除session

        		String password1 = form.getPassword(); // 密码
        		String password=AESWithJCE.getResult(mcrypt_key_1,password1);
                validatePassword(request, password);
            } catch (TransactionException e) {
                if (e.getCode().equals(
                        "error.transaction.pay_password_error_logout")) {// 向session设置错误消息，且强制登出
                    request.getSession().setAttribute("payPasswordErrorMsg",
                            getAppExceptionMessage(request, e));
                    return mapping.findForward("logout");
                } else {
                    throw e;
                }
            }

            Transaction trans = createTransaction(form);
            request.setAttribute("transaction", trans);
            try {
                // 保存交易对方记录
                Account account = trans.getDebit().getAccount(); // 交易本方为付款方
                Account peerAccount = trans.getCredit().getAccount(); // 交易对方为收款方
                savePeerInnerAccount(account, peerAccount);

                if (isPersonAccount(debitAccount) || fromMerchant) { // 个人用户或商户支付请求
                    // 如果为商户支付请求，则设置商户数据
                    if (fromMerchant) {
                        UnsPayRequest unsPayRequest = getMerchantUnsPayRequest(request
                                .getSession());
                        WebPayService webPayService = (WebPayService) IPBAppFactory
                                .getObj(ForeDict.SERVICE_WEB_PAY);
                        webPayService.wireTransactionFormMerchant(trans,
                                unsPayRequest);
                    }
                    // 保存交易，并更新账户金额限制信息
                    getTransactionTemplate().saveTransactionWithAccountLimit(
                            trans, debitAccount);
                } else { // 企业用户且非商户支付请求
                    AccountSummary accountsummary = WeatherUtil
                            .getLoingInfoFromSession(request);
                    String operatorId = accountsummary.getOperatorCode() == null ? null
                            : accountsummary.getOperatorCode().toString();
                    Operator operator = operatorId == null ? null
                            : accountsummary
                                    .getOperatorByIdInstance(operatorId);
                    trans.setOperatorSeq(operatorId);
                    getEsPrePayTransService().createEsPrePayTrans(trans,
                            debitAccount, operator);
                }
                postMerchant(request, trans);

                // 本应在此处把交易对方添加到预设账户列表里，但有时写进数据库会出错，故移到上面。

                // 只有个人用户才发送邮件和短信提醒,企业用户还需要审核,审核前不发邮件和短信
                if (isPersonAccount(debitAccount)) {
                    // 发送通知
                    sendNotice(request, trans);
                }
                
                // 风控检查
                accountTemplate.confirmToRuleByTransfer(amount.toString(),request);
                
            } catch (RuntimeException e) {
                throw TransactionException.TRANSACTION_FAILED;
            }
            resetToken(request);
        } catch (TransactionException e) {
            // 处理业务逻辑异常
            handleAppException(mapping, actionForm, request, response, e);
            // 跳转到第2步，之前重新装载部分数据
            request.setAttribute("subAccount", debitSubAccount);
            // 加载是否需要输入支付密码
            loadRequiredPassword(request);
            // 设置为上一步的步骤序数，防止序数与步骤不同步
            form.setPreviousStep();
            return mapping.findForward(ForeDict.FORWARD_STEP_2);
        }
        return mapping.findForward(ForeDict.FORWARD_STEP_3);
    }

    private void sendNotice(HttpServletRequest request, Transaction trans)
            throws Exception {
        SetUpUses suu = new SetUpUses();
        String url = WeatherUtil.getRootFromSession(request);
        suu.sendSetup(trans, trans.getDebit(), Constant.MODEL_TYPE_PAYMONEY,
                trans.getDebitFee().toString(), ConvertUtil.parseDec(
                        new Double(trans.getAmount().doubleValue()
                                + trans.getDebitFee().doubleValue()), "0.00"),
                url, null);
        suu.sendSetup(trans, trans.getCredit(), Constant.MODEL_TYPE_PAYMONEY,
                trans.getCreditFee().toString(), ConvertUtil.parseDec(
                        new Double(trans.getAmount().doubleValue()
                                - trans.getCreditFee().doubleValue()), "0.00"),
                url, null);
    }
}
